/*
 * Copyright © 2008 University of Houston
 * All rights reserved.
 */

#include <iostream>
#include <stdio.h>
#include <vector>

#include "analyzer.h"
#include "algorithm.h"
#include "logger.h"
#include "session.h"
#include "util.h"

using namespace std;

void sessionAnalyzer::initialize(session* sess, filter* filter, algorithm *alg)
{
	ourSession = sess;
	ourFilter = filter;
	ourFilter->initializeVars();
	ourAlg = alg;
	ourAlg->initializeVars();
}

void sessionAnalyzer::simulate(session *sess, filter* filter, algorithm* alg, 
		int sessID, string logfile)
{
	session s;
	s.setAnalyzer( this );
	initialize(&s, filter, alg);
	alg->initializeResultList(sessID, logfile);
    packetLogger l;	
	for(int i = 0; i < sess->getNumPackets(); i++ )
	{
		s.addPacket( (*sess)[i] );
	}
}

void sessionAnalyzer::update()
{
    timedHeader th = ourSession->getLatestPacket();
	ourAlg->startAnalysis(&th, ourFilter->update(&th));
}

analyzerResultList* sessionAnalyzer::getResultList()
{
	return ourAlg->getResultList();
}

bool sessionAnalyzer::recreate (vector<string> *logs, 
								vector<analyzerResultList> *v,
								int filterID,
								int algID)
{
	for (u_int i = 0; i < logs->size(); i++)
		sessionAnalyzer::loadFile((*logs)[i],
						   v,
						   filterID,
						   algID);

	return true;
}


void sessionAnalyzer::loadFile(string logfile,
						vector<analyzerResultList>* v,
						int filterID,
						int algID)
{

	packetLogger 				logger;
	int 						lastSession = 0;
	
	// Load the session from the log file.
	if ( !logger.init(logfile, "r"))
	{
		ERROR("File \'" << logfile << "\' could not be initalized")
		return;
	}
	
	lastSession = logger.getLastSessionNumber();
	
	for (int sessNum = 0; sessNum < lastSession; sessNum++)
	{
		// Create our session and analyzer object.
		session 		sess;
		sessionAnalyzer	ana;
		
		// Load the session
		if (!logger.loadSessionFromLog(logfile, &sess, sessNum))
		{
			ERROR("Could not perform analysis on session " 
					<< sessNum << " in log " << logfile)
			continue;
		}		
		
		// Allocate our filter/alg objects
		filter 		*filt = filter::getFilter(filterID);
		algorithm	*alg = algorithm::getAlg(algID);
		DEBUG("Recreating Session " << sessNum << " from file " << logfile)

		// Perform the analysis
		sess.setAnalyzer(&ana);
		ana.simulate(&sess, filt, alg, sessNum, logfile);

		// Add the results
		if (ana.getResultList()->size() == 0)
			WARNING("Session " << sessNum << " from file " << logfile 
				 		<< " had result list size 0... Skipping")
		else
			v->push_back(*ana.getResultList());
		
		// Deallocate
		delete filt;
		delete alg;
	}
	
}

resultsAnalyzer::resultsAnalyzer(const vector <resFilterPair> *resultsFilters,
				const vector<analyzerResultList> *normal,
				const vector<analyzerResultList> *longChains,
				const vector<analyzerResultList> *shortChains)
{
	rNormal 		= *normal;
	rLong			= *longChains;
	rShort  		= *shortChains;
	resFilters		= *resultsFilters;
	
	doAnalysis();
}

void	resultsAnalyzer::doAnalysis()
{
	// Empty the composite vector if it has not already been emptied.
	rComposite.clear();
	
	// Temp vars...
	char 	resFilterName 	= 0;
	float	resFilterParm	= 0.0f;
	vector<analyzerResultList>	temp;
	
	for(uint filt=0; filt < resFilters.size(); filt++)
	{
		// Get the filter parameters
		resFilterName = resFilters[filt].filterName;
		resFilterParm = resFilters[filt].filterParameter;
		
		// Create the filter object
		resultsFilter *f = resultsFilter::getFilter(resFilterName, resFilterParm);
		
		// Perform the filtering with just that filter object
		temp = doIndividualFilter(f);
		
		// Add the results to the end of the composite results list
		rExtra.insert(rComposite.end(), temp.begin(), temp.end());
		
		// Delete the filter object
		delete f;
	}
	
	// Make the results composite.  Note that we insert these results at the
	// beginning, so the last results are extra data from the filters.
	rComposite.insert(rComposite.begin(), rShort.begin(), rShort.end());
	rComposite.insert(rComposite.begin(), rLong.begin(), rLong.end());
	rComposite.insert(rComposite.begin(), rNormal.begin(), rNormal.end());
}

vector<analyzerResultList>* resultsAnalyzer::getCompositeResults()
{
	return &rComposite;
}

vector<analyzerResultList>* resultsAnalyzer::getExtra()
{
	VDEBUG("rExtra size: " << rExtra.size())
	return &rExtra;
}


vector<analyzerResultList> resultsAnalyzer::doIndividualFilter(resultsFilter* f)
{
	// Perform filtering that is done on individual lists.  For example,
	// sorting, normalizing, etc.
	doInvidualFilterOnSet(f, &rNormal);
	doInvidualFilterOnSet(f, &rShort);
	doInvidualFilterOnSet(f, &rLong);
	
	// Perform filtering that is done on more than one list.  For example,
	// determining a gap, etc.
	// return  f->doFilter(&rLong, &rShort);
	return  f->doFilter(&rShort,&rLong);
}

void resultsAnalyzer::doInvidualFilterOnSet(resultsFilter* f, vector<analyzerResultList> *r)
{
	vector<analyzerResultList>	temp;
	
	for(uint whichResult = 0; whichResult < r->size(); whichResult++)
		temp.push_back( f->doFilter( (*r)[whichResult] ) );
	
	*r = temp;
	temp.clear();
}

